#ifdef WITH_OPENGL
#pragma once
#include "renderer.h"
#include "context_opengl.h"
#include "matrix.h"
#include "matrix_stack.h"

#include <vector>
#include <string>

namespace krryn{
namespace math{ class matrix; }
namespace core{ class job_manager; }
namespace system{ class input_manager; }
namespace view{ class camera; }
namespace system_imp{
	class context_opengl;
	class renderer_opengl{
	public:
		typedef system::activate_t<system::opengl_tag>* activate_ptr;

		renderer_opengl();
		void begin_scene();
		void draw(scene::renderable &a_Renderable, const math::matrix &a_Transformation);
		void end_scene();

		void set_projection_matrix(const math::matrix &a_ProjectionMatrix);
		void set_camera(const view::camera &a_Camera);

		system_imp::context_opengl &get_context() {return m_Context;}
		activate_ptr m_Activate;
	private:
		std::vector<std::string> m_Extensions;
		math::matrix m_ProjectionMatrix;

		view::camera *m_Camera;
		system_imp::context_opengl m_Context;
		math::matrix_stack m_MatrixStack;
	};
}
namespace system{
	template<>
	class renderer<opengl_tag>{
	public:
		typedef std::auto_ptr<renderer<opengl_tag> > ptr;
		typedef opengl_tag render_tag;

		template<typename _RenderTag>
		renderer(core::job_manager *a_Manager, gui::render_control<_RenderTag> &a_Control){
			attach_to(a_Control);
		};

		void attach_to(gui::render_control<opengl_tag> &a_Control){
			if(m_Renderer.m_Activate != 0) delete m_Renderer.m_Activate;

			m_Renderer.m_Activate = new activate_t<opengl_tag>(*this, a_Control);
		}

		void begin_scene(){
			m_Renderer.begin_scene();
		}

		void draw(scene::renderable &a_Renderable, const math::matrix &a_Transformation){
			m_Renderer.draw(a_Renderable, a_Transformation);
		}

		void end_scene(){
			m_Renderer.end_scene();
		}

		void set_projection_matrix(const math::matrix &a_ProjectionMatrix){
			m_Renderer.set_projection_matrix(a_ProjectionMatrix);
		}

		void set_camera(const view::camera &a_Camera){
			m_Renderer.set_camera(a_Camera);
		}

		system_imp::context_opengl &get_context() {
			return m_Renderer.get_context();
		}
	private:
		system_imp::renderer_opengl m_Renderer;
    };
}
}
#endif